; First stage loader for FAT12 floppy
; Contains everything a first sector must have
[bits 16]

[org 0x0600]

; *******************************************************************
; B I O S   P a r a m e t e r   B l o c k
; *******************************************************************
						db	0xEB, 0x3C, 0x90	; JUMP SHORT 0x3C NOP
FAT12BPB:
oem_name:				db	'MSWIN4.1'			; oem_name
bytes_per_sector:		dw	512					; bytes_per_sector
sectors_per_cluster:	db	1					; sectors_per_cluster
reserved_sector_count:	dw	1					; reserved_sector_count
table_count:			db	2					; table_count
root_entry_count:		dw	0x00e0				; root_entry_count
total_sectors_16:		dw	2880				; total_sectors_16
media_type:				db	0xf0				; media_type
table_size_16:			dw	0x0009				; table_size_16
sectors_per_track:		dw	0x0012				; sectors_per_track
head_side_count:		dw	2					; head_side_count
hidden_sector_count:	dd	0					; hidden_sector_count
total_sectors_32:		dd 	0					; total_sectors_32
; extended fat12 and fat16 stuff
bios_drive_num:			db	0x00				; bios_drive_num
reserved1:				db	0x00				; reserved1
boot_signature:			db	0x28				; boot_signature
volume_id:				dd	10666				; volume_id
volume_label:			db	'souljacker '		; volume_label
fat_type_label:			db	'FAT12   '			; fat_type_label
; *******************************************************************
; E N D   O F   B I O S   P a r a m e t e r   B l o c k
; *******************************************************************

; *******************************************************************
; A S S E M B L Y   C O D E
; *******************************************************************

; *******************************************************************
; Basic initialization
	push dword 0			; clear flags
	popf
	mov ax, 0x0000			; set up segments
	mov ds, ax
	mov es, ax
	mov ax, 0x0600			; set up stack
	mov ss, ax
	mov sp, 0x0400
	
	cli						; enable interrupts
	cld						; clear directory flag

	mov [bsDriveNumber], dl	; BIOS passes drive number in DL
; Basic initialization End
; *******************************************************************

; *******************************************************************
; Self Relocating
	mov	cx, 0x0200
	mov si, 0x7c00
	mov di, 0x0600
	rep a16 movsb
	jmp relocate_end-0x7600
relocate_end:
; Self Relocating End
; *******************************************************************

; Some sticky notes:
; 0x00000500 - 0x00007BFF	 almost 30 KiB	 RAM (guaranteed free for use)	 Conventional memory
; ; 0x00007E00	 0x0007FFFF	 480.5 KiB	 RAM (guaranteed free for use)	 Conventional memory
; I wanna load stage2 into RAM from 0x7c00 (chainloading)

; *******************************************************************
; Read sectors 1-32 (we know it's a floppy and I am too lazy)
	mov	bx,	[bsBuffer]
readfatandroot:
	mov	ax, [bsLBA]			; Get Counter
	cmp	ax, 32				; If already 32 exit
	jz	readfatandroot_end	
	inc	ax					; Counter++
	mov	[bsLBA], ax			; Store new Counter value
	call readsectorLBA		; Read sector
	mov	bx,	[bsBuffer]
	add	bx, ax
	mov	[bsBuffer], bx
	jmp	readfatandroot
readfatandroot_end:
; Read sectors End
; *******************************************************************

; *******************************************************************
; Search for LOADER file entry in root directory
	mov	bx, [bsRootEntry]
searchloader:
; Search loader in /
; Scan all entries
	mov	al, [bx]
	cmp	al, 0				; If byte 0 in entry is 0 exit and halt
	jz	halt
	cmp	al, 0xE5			; If byte 0 in entry is 0xE5 ignore entry
	jz	searchloader_continue
	mov	al, [bx + 11]		; If byte 11 in entry matches one of these: 0x08/0x10 ignore entry
	test al, 0x18
	jnz	searchloader_continue
;	We found a FILE entry
;	If byte 0-10 contain the string 'LOADER  SYS' exit and load the file
	mov	cx, 10				; Set counter (10 to 0)
	mov	si, bsLoaderName	; Set string to search for in source index
	mov	di, [bsRootEntry]	; Set string to search in in destination index
compname:
	mov al, [ds:si]			; Load next char of both strings
	mov bl, [es:di]
	cmp al, bl				; If compare is not OK scan next entry
	jnz searchloader_continue
	jcxz searchloader_end	; If counter is 0 so we got Success
	dec cx					; Update counters
	inc	si
	inc	di
	jmp compname			; Compare next char
searchloader_continue:
	mov	bx, [bsRootEntry]	; Select next entry
	add bx, 32
	mov	[bsRootEntry], bx
	jmp	searchloader
searchloader_end:
; Search for LOADER End
; *******************************************************************

; *******************************************************************
; Load stage 2
	mov	bx, [bsRootEntry]	; Load first sector number in ax
	mov ax, [bx + 26]
	mov bx, 0x7c00			; Load buffer for stage 2
	mov [bsBuffer], bx
loadloader:
	push ax					; Store for next calculation
	add ax, 31				; Get real LBA
	call readsectorLBA
	mov	bx, [bsBuffer]		; Add Read bytes to bsBuffer
	add	bx, ax
	mov	[bsBuffer], bx
	pop ax					; Get current entry
	mov cx, ax
	and cx, 0x0001
	mov bx, ax
	shr ax, 1				; Divide by 2
	add ax, bx				; And add 
	mov bx, [bsFatPtr]
	add bx, ax
	mov ax, [bx]
	jcxz iseven
	shr ax, 4
	jmp isodd
iseven:
	and ax, 0x0fff
isodd:
	cmp ax, 0xff7			;
	je halt					; Bad sector :(
	cmp ax, 0xff8			; Test if last sector
	jge loadloader_end		; Jupt to end
	mov bx, [bsBuffer]
	jmp loadloader
loadloader_end:
; Load stage 2 End
; *******************************************************************

; So, we are going to run the second stage...
	xor dx, dx
	mov dl, [bsDriveNumber]	; pass disk as a parameter to stage2
	mov bx, FAT12BPB		; Pass BPB pointer

	jmp 0x7600

; *******************************************************************
; Routine: readsectorLBA AX is LBA BX is destination, returns ax=bytes read
readsectorLBA:
	push bx					; Remember address (I suck at assembly)
	mov bx, [sectors_per_track]
	cdq
	div bx					; ax = Temp = LBA/sectors_per_track
	inc dx					; Sector = (LBA % (sectors_per_track)) + 1
	mov [bsSector], dx
	mov bx, [head_side_count]
	cdq
	div bx					; al = Cylinder = Temp / (head_side_count)
							; dx = Head = Temp % (head_side_count)
	shl dx, 8				; dh = dl = head
	mov dl,	[bsDriveNumber]	; Drive
	mov ch,	al				; Cilinder
	mov cl, [bsSector]		; CL = Sector | ((cylinder >> 2) & 0xC0);
	shr al, 2
	and al, 0xC0
	or	cl, al
	
;	mov bx, 0x0000			; Address ES:BX
;	mov es,	bx				; Buffer Address Pointer
	pop bx					; Get address
	
	mov al, 0x01			; Sectors to read
	mov ah,	0x02			; Read Sectors From Drive
	int 0x13
	mov ax, [bytes_per_sector]
	ret
; readsectorLBA End
; *******************************************************************

halt:
	hlt
	jmp $

bsLBA:			dw		0
bsFatPtr:		dw		0x0A00
bsBuffer:		dw		0x0A00
bsRootEntry:	dw		0x2E00
bsSector:		resw	1
bsDriveNumber:	resb	1
bsLoaderName:	db		'LOADER  SYS'

; *******************************************************************
; E N D   O F   A S S E M B L Y   C O D E
; *******************************************************************

; *******************************************************************
; Z E R O   P A D   A N D   B O O T   S I G N A T U R E
; *******************************************************************
times	510-($-$$)	db	0
dw		0xAA55
; *******************************************************************
; E N D   O F   Z E R O   P A D   A N D   B O O T   S I G N A T U R E
; *******************************************************************
